package org.example.finalsecurities.utils;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.*;
import org.example.finalsecurities.entity.*;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 爬虫工具类
 * 功能：
 * 1. 爬取中国指数
 * 2. 爬取新股上市日历
 * 3. 爬取证券快讯
 * 4. 爬取港股资金流
 * 5. 爬取板块资金流今日涨跌幅
 *
 * @author : [CaiJianbin]
 * @version : [v1.0]
 */

public class CrawlerUtil {
    private static final String STOCK_INDEX_API_URL = "https://push2.eastmoney.com/api/qt/clist/get"; // 中国指数API URL
    private static final String NEW_STOCK_CALENDAR_URL = "https://vip.stock.finance.sina.com.cn/corp/go.php/vRPD_NewStockIssue/page/1.phtml"; // 新股上市日历URL
    private static final String STOCK_ALERT_URL = "https://kuaixun.eastmoney.com"; // 证券快讯URL
    private static final String FLOW_INFO_API_URL = "https://push2.eastmoney.com/api/qt/kamt/get"; // 港股资金流API URL
    private static final String CHANGE_INFO_URL = "https://data.eastmoney.com/bkzj/hy.html"; // 板块资金流今日涨跌幅URL
    private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36";

//    static {
//        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
//        List<ch.qos.logback.classic.Logger> loggerList = loggerContext.getLoggerList();
//        loggerList.forEach(logger -> {
//            logger.setLevel(Level.OFF);
//        });
//    }

    /**
     * @author CaiJianbin
     * @description 爬取股票指数
     * @param
     * @return java.util.List<org.example.finalsecurities.entity.StockIndex>
     */
    public static List<StockIndex> crawlChinaIndex(){
        // 构建请求参数
        String timestamp = String.valueOf(System.currentTimeMillis());
        String url = buildStockIndexApiUrl(timestamp);

        try {
            String response = sendGetRequest(url);

            List<StockIndex> stockIndexes = parseStockIndex(response);

            // 该股票指数中前9个为中国指数
            List<StockIndex> chinaIndexes = new ArrayList<>();
            for(int i = 0; i < 9; i++){
                chinaIndexes.add(stockIndexes.get(i));
            }

            return chinaIndexes;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @author CaiJianbin
     * @description 爬取新股上市日历
     * @param
     * @return java.util.List<org.example.finalsecurities.entity.NewStockCalendarInfo>
     */
    public static List<NewStockCalendarInfo> crawlNewStockCalendar() {
        Date now = new Date();
        List<NewStockCalendarInfo> newStockCalendarInfos = new ArrayList<>();
        try {
            // 使用 Jsoup 连接到指定 URL 并获取 HTML 文档
            Document doc = Jsoup.connect(NEW_STOCK_CALENDAR_URL).get();
            // 找到 id 为 NewStockTable 的表格
            Element table = doc.getElementById("NewStockTable");
            if (table != null) {
                // 找到表格中所有的行
                Elements rows = table.select("tr");
                // 从第三行开始遍历
                for (int i = 3; i < rows.size(); i++) {
                    Element row = rows.get(i);
                    // 获取行中所有的单元格
                    Elements cells = row.select("td");
                    if (cells.size() >= 4) {
                        // 提取证券简称
                        String abbreviation = cells.get(2).text().trim();
                        // 提取上市日期
                        String releaseDate = cells.get(3).text().trim();
                        // 创建 newStockCalendarInfo 对象并添加到列表中
                        NewStockCalendarInfo newStockCalendarInfo = new NewStockCalendarInfo();
                        newStockCalendarInfo.setAbbreviation(abbreviation);
                        newStockCalendarInfo.setReleaseDate(releaseDate);
                        newStockCalendarInfo.setCreateTime(now);
                        newStockCalendarInfo.setUpdateTime(now);

                        newStockCalendarInfos.add(newStockCalendarInfo);
                    }
                }
            }
            return newStockCalendarInfos;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @author CaiJianbin
     * @description 爬取证券快讯
     * @param
     * @return java.util.List<org.example.finalsecurities.entity.StockAlert>
     */
    public static List<StockAlert> crawlStockAlert() {
        Date now = new Date();
        List<StockAlert> stockAlerts = new ArrayList<>();
        WebClient browser = new WebClient();
        browser.getOptions().setCssEnabled(false);
        browser.getOptions().setJavaScriptEnabled(true);
        browser.getOptions().setThrowExceptionOnScriptError(false);
        try {
            HtmlPage htmlPage = browser.getPage(STOCK_ALERT_URL);
            browser.waitForBackgroundJavaScript(3000);
            Document document = Jsoup.parse(htmlPage.asXml());
            Elements newsItems = document.select(".news_item");

            for (Element newsItem : newsItems) {
                String newsTime = newsItem.select(".news_time").text().trim();

                // 优先获取 <b> 标签内的标题
                String newsTitle = newsItem.select(".news_detail_text b").text().trim();

                // 若无 <b> 标签，则从 news_detail_text 中提取第一个逗号前的内容
                if (newsTitle.isEmpty()) {
                    String fullText = newsItem.select(".news_detail_text").text().trim();
                    int commaIndex = fullText.indexOf("，"); // 使用中文逗号
                    if (commaIndex > 0) {
                        newsTitle = fullText.substring(0, commaIndex);
                    } else {
                        // 若连中文逗号也没有，直接使用完整文本（避免空标题）
                        newsTitle = fullText.isEmpty() ? "无标题新闻" : fullText;
                    }
                }

                newsTitle = newsTitle.replaceAll("【|】", "");

                // 处理特殊情况：标题为空时跳过（或设置默认值）
                if (newsTitle.isEmpty()) {
                    continue;
                }

                StockAlert stockAlert = new StockAlert();
                stockAlert.setTitle(newsTitle);
                stockAlert.setTime(newsTime);
                stockAlert.setCreateTime(now);
                stockAlert.setUpdateTime(now);
                stockAlerts.add(stockAlert);
            }
            return stockAlerts;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            browser.close(); // 确保资源释放
        }
        return null;
    }

    /**
     * @author CaiJianbin
     * @description 爬取港股资金流
     * @param
     * @return java.util.List<org.example.finalsecurities.entity.FlowInfo>
     */
    public static List<FlowInfo> crawlFlowInfo() {
        // 构建URL
        String apiUrl = buildFlowInfoApiUrl();
        try {
            // 发送 HTTP 请求并获取响应
            String response = sendGetRequest(apiUrl);

            // 处理 JSON 数据
            List<FlowInfo> flowInfoList = parseFlowInfo(response);

            return flowInfoList;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @author CaiJianbin
     * @description 爬取板块资金流今日涨跌幅
     * @param
     * @return java.util.Map<java.lang.String,java.util.List<org.example.finalsecurities.entity.ChangeInfo>>
     */
    public static Map<String, List<ChangeInfo>> crawlChangeInfo() {
        Map<String, List<ChangeInfo>> changeInfoMap = new HashMap<>();
        // 配置WebClient
        try (WebClient webClient = new WebClient(BrowserVersion.CHROME)) {
            webClient.getOptions().setJavaScriptEnabled(true); // 启用JavaScript
            webClient.getOptions().setCssEnabled(false);       // 禁用CSS以提高性能
            webClient.getOptions().setThrowExceptionOnScriptError(false);
            webClient.getOptions().setTimeout(10000); // 设置超时时间

            // 访问网页
            HtmlPage page = webClient.getPage(CHANGE_INFO_URL);

            // 等待JavaScript执行完成
            webClient.waitForBackgroundJavaScript(3000);

            // 点击"今日涨幅额"列进行排序
            HtmlElement changeRateHeader = page.getFirstByXPath(
                    "//th[@data-field='zd']//span[contains(@class, 'th-inner') and contains(@class, 'sortable')]"
            );
            if (changeRateHeader != null) {
                page = changeRateHeader.click();
                webClient.waitForBackgroundJavaScript(2000);
            }

            // 存储所有行业数据的列表
            List<ChangeInfo> allIndustries = new ArrayList<>();

            // 处理两页数据
            for (int pageNum = 1; pageNum <= 2; pageNum++) {
                // 等待表格加载完成
                webClient.waitForBackgroundJavaScript(2000);

                // 获取表格
                HtmlTable table = page.getFirstByXPath("//div[contains(@class, 'dataview-body')]//table");
                if (table != null) {
                    // 解析表格数据
                    for (HtmlTableRow row : table.getBodies().get(0).getRows()) {
                        // 提取行业名称
                        HtmlAnchor nameAnchor = row.getCell(1).getFirstByXPath(".//a");
                        String name = nameAnchor != null ? nameAnchor.asText() : "";

                        // 提取今日涨跌幅（修改为直接解析为Double）
                        HtmlElement changeRateElement = row.getCell(3).getFirstByXPath(".//span");
                        Double changeRate = 0.0;
                        if (changeRateElement != null) {
                            try {
                                changeRate = Double.parseDouble(changeRateElement.asText().replace("%", ""));
                            } catch (NumberFormatException e) {
                                changeRate = 0.0;
                            }
                        }

                        // 添加到列表
                        if (!name.isEmpty()) {
                            ChangeInfo changeInfo = new ChangeInfo();
                            changeInfo.setName(name);
                            changeInfo.setRateChange(changeRate);
                            allIndustries.add(changeInfo);
                        }
                    }
                }

                // 如果不是最后一页，点击下一页
                if (pageNum < 2) {
                    HtmlAnchor nextPageButton = page.getFirstByXPath(
                            "//div[contains(@class, 'dataview-pagination')]//a[@data-page='2']"
                    );
                    if (nextPageButton != null) {
                        page = nextPageButton.click();
                        webClient.waitForBackgroundJavaScript(2000);
                    }
                }
            }

            // 按涨跌幅排序
            allIndustries.sort(Comparator.comparingDouble(ChangeInfo::getRateChange).reversed());

            // 获取涨幅最大的10个行业
            List<ChangeInfo> topGainers = allIndustries.stream()
                    .filter(data -> data.getRateChange() > 0)
                    .limit(5)
                    .collect(Collectors.toList());

            // 获取跌幅最大的10个行业（涨跌幅为负数）
            List<ChangeInfo> topLosers = allIndustries.stream()
                    .filter(data -> data.getRateChange() < 0)
                    .sorted(Comparator.comparingDouble(ChangeInfo::getRateChange))
                    .limit(5)
                    .collect(Collectors.toList());

            // 将结果添加到Map中
            changeInfoMap.put("涨幅", topGainers);
            changeInfoMap.put("跌幅", topLosers);

            return changeInfoMap;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @author CaiJianbin
     * @description 解析JSON数据
     * @param jsonStr
     * @return java.util.List<org.example.finalsecurities.entity.StockIndex>
     */
    private static List<StockIndex> parseStockIndex(String jsonStr) {
        List<StockIndex> result = new ArrayList<>();

        try {
            int start = jsonStr.indexOf("(");
            int end = jsonStr.lastIndexOf(")");
            if (start > 0 && end > start) {
                jsonStr = jsonStr.substring(start + 1, end);
            }

            // 解析JSON字符串
            JSONObject root = JSON.parseObject(jsonStr);
            JSONObject data = root.getJSONObject("data");
            JSONArray diffArray = data.getJSONArray("diff");

            // 当前时间作为更新时间
            Date now = new Date();

            // 遍历每个指数数据
            for (int i = 0; i < diffArray.size(); i++) {
                JSONObject indexObj = diffArray.getJSONObject(i);

                StockIndex stockIndex = new StockIndex();
                stockIndex.setCode(indexObj.getString("f12"));
                stockIndex.setName(indexObj.getString("f14"));

                // 处理价格，将其除以100转换为实际价格
                BigDecimal price = indexObj.getBigDecimal("f2").divide(BigDecimal.valueOf(100));
                stockIndex.setPrice(price);

                stockIndex.setCreateTime(now);
                stockIndex.setUpdateTime(now);

                result.add(stockIndex);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * @author CaiJianbin
     * @description 解析资金流数据
     * @createTime  2025/5/21
     * @param jsonpResponse
     * @return java.util.List<org.example.finalsecurities.entity.FlowInfo>
     */
    private static List<FlowInfo> parseFlowInfo(String jsonpResponse) {
        List<FlowInfo> dataList = new ArrayList<>();

        try {
            // 去除 JSONP 回调函数包装
            String jsonStr = jsonpResponse.replaceAll("^[^(]+\\(|\\)$", "");

            // 解析 JSON
            JSONObject jsonObject = JSONObject.parseObject(jsonStr);
            JSONObject data = jsonObject.getJSONObject("data");

            if (data != null) {
                // 提取沪港通数据 (sh2hk)
                JSONObject sh2hk = data.getJSONObject("sh2hk");
                if (sh2hk != null) {
                    double netBuy = sh2hk.getDoubleValue("netBuyAmt");
                    double totalAmount = sh2hk.getDoubleValue("buySellAmt");

                    // 转换为 BigDecimal
                    BigDecimal formattedNetBuy = NumberUtil.doubleToBigDecimal(netBuy);
                    BigDecimal formattedTotal = NumberUtil.doubleToBigDecimal(totalAmount);

                    FlowInfo flowInfo = new FlowInfo();
                    flowInfo.setName("沪>港");
                    flowInfo.setPurchases(formattedNetBuy);
                    flowInfo.setTotal(formattedTotal);

                    dataList.add(flowInfo);
                }

                // 提取深港通数据 (sz2hk)
                JSONObject sz2hk = data.getJSONObject("sz2hk");
                if (sz2hk != null) {
                    double netBuy = sz2hk.getDoubleValue("netBuyAmt");
                    double totalAmount = sz2hk.getDoubleValue("buySellAmt");

                    // 转换为 BigDecimal
                    BigDecimal formattedNetBuy = NumberUtil.doubleToBigDecimal(netBuy);
                    BigDecimal formattedTotal = NumberUtil.doubleToBigDecimal(totalAmount);

                    FlowInfo flowInfo = new FlowInfo();
                    flowInfo.setName("深>港");
                    flowInfo.setPurchases(formattedNetBuy);
                    flowInfo.setTotal(formattedTotal);

                    dataList.add(flowInfo);
                }
            }
        } catch (Exception e) {
            System.err.println("解析JSON失败: " + e.getMessage());
            e.printStackTrace();
        }

        return dataList;
    }

    /**
     * @author CaiJianbin
     * @description 构建股票指数API URL
     * @param timestamp
     * @return java.lang.String
     */
    private static String buildStockIndexApiUrl(String timestamp) {
        Map<String, String> params = new HashMap<>();
        params.put("np", "1");
        params.put("fltt", "1");
        params.put("invt", "2");
        params.put("fs", "i:1.000001,i:0.399001,i:0.399005,i:0.399006,i:1.000300,i:100.HSI,i:100.HSCEI,i:124.HSCCI,i:100.TWII,i:100.N225,i:100.KOSPI200,i:100.KS11,i:100.STI,i:100.SENSEX,i:100.KLSE,i:100.SET,i:100.PSI,i:100.KSE100,i:100.VNINDEX,i:100.JKSE,i:100.CSEALL");
        params.put("fields", "f12,f14,f2");        // 仅获取必要字段
        params.put("pn", "1");
        params.put("pz", "100");
        params.put("po", "1");
        params.put("ut", "fa5fd1943c7b386f172d6893dbfba10b");
        params.put("dect", "1");
        params.put("wbp2u", "%7C0%7C0%7C0%7Cweb");
        params.put("_", timestamp);

        return STOCK_INDEX_API_URL + "?" + buildQueryString(params);
    }

    /**
     * @author CaiJianbin
     * @description 构建资金流API URL
     * @param
     * @return java.lang.String
     */
    private static String buildFlowInfoApiUrl() {
        long timestamp = System.currentTimeMillis();
        String randomCallback = "jQuery" + NumberUtil.generateRandomNumber(20) + "_" + timestamp;

        // 构建fields参数（根据新API调整）
        String fields1 = "f1,f2,f3,f4";
        String fields2 = "f51,f52,f53,f54,f56,f60,f61,f62,f63,f65,f66";

        return String.format("%s?fields1=%s&fields2=%s&ut=fa5fd1943c7b386f172d6893dbfba10b&cb=%s&_=%d",
                FLOW_INFO_API_URL, fields1, fields2, randomCallback, timestamp);
    }

    /**
     * @author CaiJianbin
     * @description 发送GET请求
     * @param apiUrl
     * @return java.lang.String
     */
    private static String sendGetRequest(String apiUrl) throws IOException {
        URL url = new URL(apiUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        // 设置请求头
        connection.setRequestMethod("GET");
        connection.setRequestProperty("User-Agent", USER_AGENT);

        // 获取响应状态码
        int responseCode = connection.getResponseCode();

        // 处理错误响应
        if (responseCode == HttpURLConnection.HTTP_OK) {
            // 成功响应
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
                StringBuilder response = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    response.append(line);
                }
                return response.toString();
            }
        } else {
            // 错误响应
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(connection.getErrorStream(), StandardCharsets.UTF_8))) {
                StringBuilder errorResponse = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    errorResponse.append(line);
                }
                throw new IOException("HTTP错误 " + responseCode + ": " + errorResponse.toString());
            }
        }
    }

    /**
     * @author CaiJianbin
     * @description 构建查询字符串
     * @param params
     * @return java.lang.String
     */
    private static String buildQueryString(Map<String, String> params) {
        return params.entrySet().stream()
                .map(entry -> entry.getKey() + "=" + entry.getValue())
                .reduce((a, b) -> a + "&" + b)
                .orElse("");
    }

}
